package com.noble.meether.chat.ui.agora.model;

import io.agora.rtc.Constants;
import io.agora.rtc.IRtcEngineEventHandler;

/**
 * 音视频通信回调  根据需求实现对应方法，不做耗时或会引起阻塞的API（如： SendMessage）
 * <p>
 * {@see 'https://docs.agora.io/cn/2.0/product/Video/API%20Reference/communication_android_video?platform=Android'}
 * <p>
 * Created by Su on 2017/4/17.
 */
public abstract class AGEventHandler {
    public AGEventHandler() {
    }

    /**
     * 加入频道成功
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onjoinchannelsuccess'}
     */
    public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
    }

    /**
     * 离开频道
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#leave-channel-callback-onleavechannel'}
     */
    public void onLeaveChannel(IRtcEngineEventHandler.RtcStats stats) {
    }

    /**
     * 网络等原因与服务器失联后自动重连成功
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#rejoin-channel-callback-onrejoinchannelsuccess'}
     */
    public void onRejoinChannelSuccess(String channel, int uid, int elapsed) {
    }

    /**
     * 语音路由已变更回调  0 耳机 3 外放
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#audio-route-changed-callback-onaudioroutechanged'}
     */
    public void onAudioRouteChanged(int routing) {
    }

    /**
     * 通信用户离线
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#other-user-offline-callback-onuseroffline'}
     */
    public void onUserOffline(int uid, int reason) {
    }

    /**
     * 通信连接丢失
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#connection-lost-callback-onconnectionlost'}
     */
    public void onConnectionLost() {
    }

    /**
     * 连接中断回调
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#connection-interrupted-callback-onconnectioninterrupted'}
     */
    public void onConnectionInterrupted() {
    }

    /**
     * 网络质量报告回调： 2s触发一次
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#network-quality-callback-onlastmilequality'}
     */
    public void onLastmileQuality(int quality) {
    }

    /**
     * 频道内网络质量报告回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onnetworkquality'}
     */
    public void onNetworkQuality(int uid, int txQuality, int rxQuality) {
    }

    /**
     * 特殊错误回调
     */
    public void onExtraCallback(int type, Object... data) {
    }

    /**
     * 警告回调
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#warning-occurred-callback-onwarning'}
     */
    public void onWarning(int warn) {
    }


    // ----------------------------------  视频功能回调 --------------------------------------------

    /**
     * 本地视频显示回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onfirstlocalvideoframe'}
     */
    public void onFirstLocalVideoFrame(int width, int height, int elapsed) {
    }

    /**
     * 远端视频显示回调
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#first-remote-video-frame-displayed-callback-onfirstremotevideoframe'}
     */
    public void onFirstRemoteVideoFrame(int uid, int width, int height, int elapsed) {
    }

    /**
     * 首次绑定远端视频
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#first-remote-video-frame-received-and-decoded-callback-onfirstremotevideodecoded'}
     */
    public void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed) {
    }

    /**
     * 其他用户停止/重启视频回调
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#other-user-paused-resumed-video-callback-onusermutevideo'}
     */
    public void onUserMuteVideo(int uid, boolean muted) {
    }

    /**
     * 其他用户启用/关闭视频
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#other-user-enabled-disabled-video-callback-onuserenablevideo'}
     */
    public void onUserEnableVideo(int uid, boolean enabled) {
    }

    /**
     * 远端视频统计回调
     * <p>
     * {@see 'https://docs.agora.io/cn/user_guide/API/android_api.html#remote-video-statistics-callback-onremotevideostats'}
     */
    public void onRemoteVideoStats(IRtcEngineEventHandler.RemoteVideoStats stats) {
    }

    /**
     * 本地视频统计回调，2s触发
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onlocalvideostats'}
     */
    public void onLocalVideoStats(IRtcEngineEventHandler.LocalVideoStats stats) {
    }

    /**
     * 摄像头启用回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#oncameraready'}
     */
    public void onCameraReady() {
    }

    /**
     * 视频功能停止回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onvideostopped'}
     */
    public void onVideoStopped() {
    }

    /**
     * 接收到对方数据流消息(5s)
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onstreammessage'}
     */
    public void onStreamMessage(int uid, int streamId, byte[] data) {
    }

    /**
     * 接受对方数据流消息错误回调(5s内未收到)
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onstreammessageerror'}
     */
    public void onStreamMessageError(int uid, int streamId, int code, int missed, int cached) {
    }

//    /**
//     * Channel key已过期回调
//     * <p>
//     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#channel-key-onrequestchannelkey'}
//     */
//    public void onRequestChannelKey() {
//    }

    /**
     * 伴奏播放已结束回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onaudiomixingfinished'}
     */
    public void onAudioMixingFinished() {
    }

    /**
     * Rtc Engine统计数据回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#rtc-engine-onrtcstats'}
     */
    public void onRtcStats(IRtcEngineEventHandler.RtcStats stats) {
    }

    /**
     * 其他用户静音回调
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onusermuteaudio'}
     */
    public void onUserMuteAudio(int uid, boolean muted) {
    }

    /**
     * 其他用户加入当前频道
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onuserjoined'}
     */
    public void onUserJoined(int uid, int elapsed) {
    }

    /**
     * 说话声音音量提示
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onaudiovolumeindication'}
     */
    public void onAudioVolumeIndication(IRtcEngineEventHandler.AudioVolumeInfo[] speakerInfos, int totalVolume) {
    }

    /**
     * 音频质量
     * <p>
     * {@see 'https://document.agora.io/cn/1.14/api/communication_video_android.html#onaudioquality'}
     */
    public void onAudioQuality(int uid, int quality, short delay, short lost) {
    }

    public static class EventType {
        public static final int EVENT_TYPE_ON_DATA_CHANNEL_MSG = 3;
        public static final int ON_USER_VIDEO_MUTED = 6;
        public static final int EVENT_TYPE_ON_USER_AUDIO_MUTED = 7;
        public static final int EVENT_TYPE_ON_SPEAKER_STATS = 8;
        public static final int ON_AGORA_MEDIA_ERROR = 9;            // 声网SDK运行时错误(网络或媒体)
        public static final int EVENT_TYPE_ON_USER_VIDEO_STATS = 10;
        public static final int EVENT_TYPE_ON_APP_ERROR = 13;
        public static final int EVENT_TYPE_ON_AUDIO_ROUTE_CHANGED = 18;

        public EventType() {
        }
    }

    /**
     * SDK回调错误码
     * <p>
     * {https://docs.agora.io/cn/1.8/user_guide/troubleshooting/error.html}
     */
    protected static String errorCode(int err) {
        String result = "错误代码";
        switch (err) {
            case Constants.ERR_OK:
                result = "没有错误";
                break;
            case Constants.ERR_FAILED:
                result = "一般性的错误(没有明确归类的错误原因)";
                break;
            case Constants.ERR_INVALID_ARGUMENT:
                result = "API 调用了无效的参数。例如指定的频道名含有非法字符。";
                break;
            case Constants.ERR_NOT_READY:
                result = "SDK 的模块没有准备好，例如某个 API 调用依赖于某个模块，但该模块尚未准备提供服务。";
                break;
            case Constants.ERR_NOT_SUPPORTED:
                result = "SDK 不支持该功能。";
                break;
            case Constants.ERR_REFUSED:
                result = "调用被拒绝。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_BUFFER_TOO_SMALL:
                result = "传入的缓冲区大小不足以存放返回的数据。";
                break;
            case Constants.ERR_NOT_INITIALIZED:
                result = "SDK 尚未初始化，就调用其 API。";
                break;
            case Constants.ERR_NO_PERMISSION:
                result = "没有操作权限。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_TIMEDOUT:
                result = "API 调用超时。有些 API 调用需要 SDK 返回结果，如果 SDK 处理时间过长，会出现此错误。";
                break;
            case Constants.ERR_CANCELED:
                result = "请求被取消。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_TOO_OFTEN:
                result = "调用频率太高。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_BIND_SOCKET:
                result = "SDK 内部绑定到网络 socket 失败。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_NET_DOWN:
                result = "网络不可用。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_NET_NOBUFS:
                result = "没有网络缓冲区可用。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case Constants.ERR_JOIN_CHANNEL_REJECTED:
                result = "加入频道被拒绝。一般是因为用户已进入频道，再次调用加入频道的 API，例如 joinChannel，会返回此错误。";
                break;
            case Constants.ERR_LEAVE_CHANNEL_REJECTED:
                result = "离开频道失败。一般是因为用户已离开某频道，再次调用退出频道的API，例如 leaveChannel，会返回此错误。";
                break;
            case Constants.ERR_ALREADY_IN_USE:
                result = "资源已被占用，不能重复使用。";
                break;
            case 20:
                result = "SDK 放弃请求，可能由于请求次数太多。仅供 SDK 内部使用，不通过 API 或者回调事件返回给应用程序。";
                break;
            case 21:
                result = "Windows 下特定的防火墙设置导致 SDK 初始化失败然后崩溃。";
                break;
            case Constants.ERR_INVALID_APP_ID:
                result = "无效的 App ID";
                break;
            case Constants.ERR_INVALID_CHANNEL_NAME:
                result = "无效的频道名";
                break;
            case Constants.ERR_NOT_IN_CHANNEL:
                result = "用户不在频道内。";
                break;
            case Constants.ERR_SIZE_TOO_LARGE:
                result = "数据太大。";
                break;
            case Constants.ERR_BITRATE_LIMIT:
                result = "码率受限。";
                break;
            case Constants.ERR_LOAD_MEDIA_ENGINE:
                result = "加载媒体引擎失败";
                break;
            case Constants.ERR_START_CALL:
                result = "打开本地音视频设备、启动通话失败";
                break;
            case Constants.ERR_ADM_GENERAL_ERROR:
                result = "音频设备模块出现一般性错误（没有明显归类的错误）。";
                break;
            case Constants.ERR_ADM_JAVA_RESOURCE:
                result = "语音模块: 使用 java 资源出现错误。";
                break;
            case Constants.ERR_ADM_SAMPLE_RATE:
                result = "语音模块: 设置的采样频率出现错误。";
                break;
            case Constants.ERR_ADM_INIT_PLAYOUT:
                result = "语音模块: 初始化播放设备出现错误。";
                break;
            case Constants.ERR_ADM_START_PLAYOUT:
                result = "语音模块: 启动播放设备出现错误。";
                break;
            case Constants.ERR_ADM_STOP_PLAYOUT:
                result = "语音模块: 停止播放设备出现错误。";
                break;
            case Constants.ERR_ADM_INIT_RECORDING:
                result = "语语音模块: 初始化录音设备时出现错误。";
                break;
            case Constants.ERR_ADM_START_RECORDING:
                result = "语音模块: 启动录音设备出现错误。";
                break;
            case Constants.ERR_ADM_STOP_RECORDING:
                result = "语音模块: 停止录音设备出现错误。";
                break;
            case Constants.ERR_ADM_RUNTIME_PLAYOUT_ERROR:
                result = "语音模块: 运行时播放出现错误。";
                break;
            case Constants.ERR_ADM_RUNTIME_RECORDING_ERROR:
                result = "语音模块: 运行时录音错误。";
                break;
            case Constants.ERR_ADM_RECORD_AUDIO_FAILED:
                result = "语音模块: 录制失败";
                break;
            case Constants.ERR_ADM_INIT_LOOPBACK:
                result = "语音模块: 初始化 loopback 设备错误。";
                break;
            case Constants.ERR_ADM_START_LOOPBACK:
                result = "语音模块: 启动 loopback 设备错误。";
                break;
            case 1027:
                result = "语音模块: 没有使用 ADM 的权限";
                break;
            case Constants.ERR_START_CAMERA:
                result = "打开本地摄像头失败";
                break;
            case Constants.ERR_TOKEN_EXPIRED:
                result = "当前使用的 Channel Key过期，不再有效";
                break;
        }
        return result;
    }

    /**
     * SDK回调警告码
     */
    protected static String warnCode(int warn) {
        String result = "警告码";
        switch (warn) {
            case Constants.WARN_PENDING:
                result = "请求处于待定状态。一般是由于某个模块还没准备好，请求被延迟处理。";
                break;
            case Constants.WARN_NO_AVAILABLE_CHANNEL:
                result = "没有可用的频道资源。可能是因为服务端没法分配频道资源。";
                break;
            case Constants.WARN_LOOKUP_CHANNEL_TIMEOUT:
                result = "查找频道超时。在加入频道时SDK先要查找指定的频道，出现该警告一般是因为网络太差，连接不到服务器。";
                break;
            case Constants.WARN_LOOKUP_CHANNEL_REJECTED:
                result = "查找频道请求被服务器拒绝。意味着服务器主动拒绝了请求, 服务器可能没有办法处理这个请求或请求是非法的。";
                break;
            case Constants.WARN_OPEN_CHANNEL_TIMEOUT:
                result = "打开频道超时。查找到指定频道后，SDK 接着打开该频道，超时一般是因为网络太差，连接不到服务器。";
                break;
            case Constants.WARN_OPEN_CHANNEL_REJECTED:
                result = "打开频道请求被服务器拒绝。意味着服务器主动拒绝了请求, 服务器可能没有办法处理该请求或该请求是非法的。";
                break;
            case Constants.WARN_SET_CLIENT_ROLE_TIMEOUT:
                result = "设置用户角色超时。服务器可能没有办法处理该请求或该请求是非法的。";
                break;
            case Constants.WARN_SET_CLIENT_ROLE_NOT_AUTHORIZED:
                result = "用户没有权限进行该操作";
                break;
            case Constants.WARN_AUDIO_MIXING_OPEN_ERROR:
                result = "调用 startAudioMixing() 时传入了不正确或不完整的文件";
                break;
            case Constants.WARN_ADM_RUNTIME_PLAYOUT_WARNING:
                result = "音频设备模块: 运行时播放设备出现警告。";
                break;
            case Constants.WARN_ADM_RUNTIME_RECORDING_WARNING:
                result = "音频设备模块: 运行时录音设备出现警告。";
                break;
            case Constants.WARN_ADM_RECORD_AUDIO_SILENCE:
                result = "音频设备模块: 没有采集到有效的声音数据。";
                break;
//            case Constants.WARN_ADM_PLAYOUT_MALFUNCTION:
//                result = "音频设备模块: 播放设备出现故障。";
//                break;
//            case Constants.WARN_ADM_RECORD_MALFUNCTION:
//                result = "音频设备模块: 录制设备出现故障。";
//                break;
            case 1031:
                result = "音频设备模块: 录制声音过小。";
                break;
            case Constants.WARN_APM_HOWLING:
                result = "音频设备模块: 检测到啸叫。";
                break;
        }
        return result;
    }

    /**
     * 用户离线原因
     */
    protected static String offlineReason(int reason) {
        String result = "离线原因";
        switch (reason) {
            case Constants.USER_OFFLINE_QUIT:
                result = "用户主动离开";
                break;
            case Constants.USER_OFFLINE_DROPPED:
                result = " 因过长时间收不到对方数据包，超时掉线";
                break;
        }
        return result;
    }

    /**
     * 网络质量描述
     */
    protected static String netQuality(int quality) {
        String result = "unknown";
        switch (quality) {
            case Constants.QUALITY_UNKNOWN:
                result = "unknown";
                break;
            case Constants.QUALITY_EXCELLENT:
                result = "excellent";
                break;
            case Constants.QUALITY_GOOD:
                result = "good";
                break;
            case Constants.QUALITY_POOR:
                result = "poor";
                break;
            case Constants.QUALITY_BAD:
                result = "bad";
                break;
            case Constants.QUALITY_VBAD:
                result = "very bad";
                break;
            case Constants.QUALITY_DOWN:
                result = "net down";
                break;
        }
        return result;
    }
}
